﻿/* Author: Achim Schnell */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AppFx.Tokenization
{
    /// <summary>
    /// Verifies a string/char for a token.
    /// </summary>
    public abstract class Verifier : IVerifier
    {
        #region Properties

        /// <summary>
        /// The parent tokenizer of a verifier.
        /// </summary>
        public ITokenizer Tokenizer { get; protected set; }

        /// <summary>
        /// The current text-buffer.
        /// </summary>
        protected string Buffer { get; set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Verifier"/> class.
        /// </summary>
        public Verifier(ITokenizer tokenizer) 
        {
            Tokenizer = tokenizer;
            Buffer = String.Empty;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets the next char that would pe processed.
        /// </summary>
        /// <returns></returns>
        protected virtual Nullable<char> PreviewNext()
        {
            return Preview(1);
        }

        /// <summary>
        /// Previews the char of the specified index.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <returns></returns>
        protected virtual Nullable<char> Preview(int index)
        {
            string buffer = Tokenizer.GetBuffer();
            if (buffer.Count() >= index + 2)
                return buffer[index + 1];
            else
                return null;
        }

        /// <summary>
        /// Reviews the last token.
        /// </summary>
        /// <returns>The last token.</returns>
        protected virtual IToken ReviewLast()
        {
            return Review(0);
        }

        /// <summary>
        /// Reviews a token..
        /// </summary>
        /// <param name="index">The index. (zero-based)</param>
        /// <returns>The token at the given index. (Reversed token-list)</returns>
        protected virtual IToken Review(int index)
        {
            var tokens = Tokenizer.GetCurrentTokens();
            if (index < tokens.Count())
                return tokens.Reverse().ElementAt(index);
            else
                return null;
        }

        /// <summary>
        /// Detects if the given char matches the token's pattern.
        /// </summary>
        /// <param name="c">Char to verify for tokenization.</param>
        /// <returns>
        /// A bool indicating if the given char matches the token's pattern.
        /// </returns>
        public abstract bool Verify(char c);

        /// <summary>
        /// Saves a given char in the verifiers string to create a token.
        /// </summary>
        /// <param name="c">The char to consume.</param>
        public virtual void Consume(char c)
        {
            Buffer = Buffer + c;
        }

        /// <summary>
        /// Resets the verifiers buffer.
        /// </summary>
        public virtual void Reset()
        {
            Buffer = String.Empty;
        }

        /// <summary>
        /// Creates the token based on the current input-pattern.
        /// </summary>
        /// <returns>An IToken containing the current input-pattern.</returns>
        protected abstract IToken CreateToken();

        /// <summary>
        /// Finalizes the current input-pattern returning a token.
        /// </summary>
        /// <returns>
        /// An IToken containing the current input-pattern.
        /// </returns>
        public virtual IToken Finalize()
        {
            IToken token = CreateToken();
            Reset();
            return token;
        }

        #endregion
    }
}
